/**
 * File: ReadLoaderController.java
 * Created by: mhaimel
 * Created on: 9 Jul 2009
 * CVS:  $Id: ReadLoaderController.java,v 1.4 2009/11/24 16:31:20 mhaimel Exp $
 */
package uk.ac.ebi.curtain.controller.loader;

import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;

import uk.ac.ebi.curtain.controller.ParallelSingleSubmitController;
import uk.ac.ebi.curtain.controller.SimpleReport;
import uk.ac.ebi.curtain.management.IControllerReport;
import uk.ac.ebi.curtain.processor.load.impl.ReadLoadProcessor;
import uk.ac.ebi.curtain.service.IdentifierFilepositionIndex;
import uk.ac.ebi.curtain.util.FileIndexWriter;
import uk.ac.ebi.curtain.utils.data.FileType;
import uk.ac.ebi.curtain.utils.data.ReadType;
import uk.ac.ebi.curtain.utils.file.FileInfo;
import uk.ac.ebi.curtain.utils.io.impl.FileIO;

/**
 * @author mhaimel
 * 
 */
public class ReadLoaderController extends ParallelSingleSubmitController<Serializable, Serializable, ReadLoadProcessor> {
	private Integer iCnt = 0;
	private final Set<IdentifierFilepositionIndex> fposSet = new CopyOnWriteArraySet<IdentifierFilepositionIndex>();
	private final AtomicReference<List<Serializable>> input = new AtomicReference<List<Serializable>>();

	@Override
	protected void singleSubmit(List<Serializable> inputList) {
		input.set(inputList);
		/* No need -> get's streamed out */
		// Integer size = getContext().getReadIndex().getSize();
		// getLog().debug("Reset Read data to read index size " + size);
		// getContext().getReadData().reset(size);

		// make space for MapLocations
		getLog().info(
				"Run GC ... "
						+ ManagementFactory.getMemoryMXBean()
								.getHeapMemoryUsage());
		System.gc();
		getLog().info(
				"GC done!"
						+ ManagementFactory.getMemoryMXBean()
								.getHeapMemoryUsage());
		// _initArraySize();
		for (FileInfo fi : getFiles()) {
			ReadLoadProcessor job = _buildJob(fi);
			submit(job);
		}
	}

	protected Collection<FileInfo> getFiles() {
		return getSequenceFiles(ReadType.getAllRead());
	}

	protected Collection<FileInfo> getSequenceFiles(ReadType... rArr) {
		List<FileInfo> fiList = new ArrayList<FileInfo>();
		for (ReadType rt : rArr) {
			fiList.addAll(getContext().getArguments().getFiles(rt,
					FileType.getSequenceTypes()));
		}
		return fiList;
	}
	
	@Override
	protected void processResult(Future<Serializable> res, ReadLoadProcessor job) {
		List<Serializable> list = input.getAndSet(null);
		if(null != list){
			for(Serializable in : list){
				interceptorHandle(in);
			}
		} else {
			interceptorHandle("Finished");
		}
//		super.processResult(res, job);
	}

	@Override
	protected void doShutdown() {
		// getContext().getReadData().clear(); // DON'T DO IT -> would loose all
		// data
		// getContext().getReadIndex().clear(); // This is the correct call!!!
		getLog().debug("Close all writer ... ");
		for (IdentifierFilepositionIndex idx : fposSet) {
			FileIO.closeQuietly(idx);
		}
		super.doShutdown();
	}

	@Override
	protected IControllerReport getReturnCall() {
		return new SimpleReport("Finished with " + iCnt + " loaded files!");
	}

	protected ReadLoadProcessor _buildJob(FileInfo input) {
		++iCnt;
		ReadLoadProcessor job = getContext().getInjector().getInstance(ReadLoadProcessor.class);
		job.setInput(input);
		job.setWriter(getWriter(input));
		return job;
	}

	private FileIndexWriter getWriter(FileInfo input) {
		IdentifierFilepositionIndex idxWriter = 
			getContext().getPositionIndex(
					getContext().currentFiles().getEntryFilePosition(
							input.getReadType()));
		fposSet.add(idxWriter);
		if (!idxWriter.isWriteable()) {
			idxWriter.setWriteOnly();
		}
		return idxWriter.getWriter();
	}
}
